package cn.com.anysdk.redis.service;

import cn.com.anysdk.redis.api.IRedisConfig;
import cn.com.anysdk.redis.api.IRedisService;
import cn.com.anysdk.redis.api.PipelineCallback;
import cn.com.anysdk.redis.api.TransactionCallback;
import cn.com.anysdk.redis.exception.RedisException;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis 服务实现类
 */
@Slf4j
public class RedisServiceImpl implements IRedisService {
    private final JedisPool jedisPool;

    public RedisServiceImpl(IRedisConfig config) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(config.getMaxTotal());
        poolConfig.setMaxIdle(config.getMaxIdle());
        poolConfig.setMinIdle(config.getMinIdle());
        poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());
        poolConfig.setTestOnBorrow(config.isTestOnBorrow());
        poolConfig.setTestOnReturn(config.isTestOnReturn());
        poolConfig.setTestWhileIdle(config.isTestWhileIdle());

        this.jedisPool = new JedisPool(poolConfig,
                config.getHost(),
                config.getPort(),
                config.getTimeout(),
                config.getPassword(),
                config.getDatabase());
    }

    @Override
    public void set(String key, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.set(key, value);
        } catch (Exception e) {
            throw new RedisException("Set key failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void set(String key, String value, long timeout, TimeUnit unit) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.setex(key, (int) unit.toSeconds(timeout), value);
        } catch (Exception e) {
            throw new RedisException("Set key with timeout failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String get(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.get(key);
        } catch (Exception e) {
            throw new RedisException("Get key failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Boolean delete(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.del(key) > 0;
        } catch (Exception e) {
            throw new RedisException("Delete key failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Boolean exists(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.exists(key);
        } catch (Exception e) {
            throw new RedisException("Check key exists failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long expire(String key, long timeout, TimeUnit unit) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.expire(key, (int) unit.toSeconds(timeout));
        } catch (Exception e) {
            throw new RedisException("Set key expire failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void hset(String key, String field, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.hset(key, field, value);
        } catch (Exception e) {
            throw new RedisException("Hset failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String hget(String key, String field) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hget(key, field);
        } catch (Exception e) {
            throw new RedisException("Hget failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Map<String, String> hgetAll(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hgetAll(key);
        } catch (Exception e) {
            throw new RedisException("HgetAll failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long hdel(String key, String... fields) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hdel(key, fields);
        } catch (Exception e) {
            throw new RedisException("Hdel failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Boolean hexists(String key, String field) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hexists(key, field);
        } catch (Exception e) {
            throw new RedisException("Hexists failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long lpush(String key, String... values) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.lpush(key, values);
        } catch (Exception e) {
            throw new RedisException("Lpush failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long rpush(String key, String... values) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.rpush(key, values);
        } catch (Exception e) {
            throw new RedisException("Rpush failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String lpop(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.lpop(key);
        } catch (Exception e) {
            throw new RedisException("Lpop failed: " + e.getMessage(), e);
        }
    }

    @Override
    public String rpop(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.rpop(key);
        } catch (Exception e) {
            throw new RedisException("Rpop failed: " + e.getMessage(), e);
        }
    }

    @Override
    public List<String> lrange(String key, long start, long end) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.lrange(key, start, end);
        } catch (Exception e) {
            throw new RedisException("Lrange failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long llen(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.llen(key);
        } catch (Exception e) {
            throw new RedisException("Llen failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long sadd(String key, String... members) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.sadd(key, members);
        } catch (Exception e) {
            throw new RedisException("Sadd failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Set<String> smembers(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.smembers(key);
        } catch (Exception e) {
            throw new RedisException("Smembers failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Boolean sismember(String key, String member) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.sismember(key, member);
        } catch (Exception e) {
            throw new RedisException("Sismember failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long srem(String key, String... members) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.srem(key, members);
        } catch (Exception e) {
            throw new RedisException("Srem failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long zadd(String key, double score, String member) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.zadd(key, score, member);
        } catch (Exception e) {
            throw new RedisException("Zadd failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Set<String> zrange(String key, long start, long end) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.zrange(key, start, end);
        } catch (Exception e) {
            throw new RedisException("Zrange failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Set<String> zrevrange(String key, long start, long end) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.zrevrange(key, start, end);
        } catch (Exception e) {
            throw new RedisException("Zrevrange failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Long zrem(String key, String... members) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.zrem(key, members);
        } catch (Exception e) {
            throw new RedisException("Zrem failed: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean tryLock(String key, String value, long timeout, TimeUnit unit) {
        try (Jedis jedis = jedisPool.getResource()) {
            String result = jedis.set(key, value, "NX", "PX", unit.toMillis(timeout));
            return "OK".equals(result);
        } catch (Exception e) {
            throw new RedisException("Try lock failed: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean releaseLock(String key, String value) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        try (Jedis jedis = jedisPool.getResource()) {
            Object result = jedis.eval(script, 1, key, value);
            return result != null && (Long) result > 0;
        } catch (Exception e) {
            throw new RedisException("Release lock failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void pipeline(PipelineCallback callback) {
        try (Jedis jedis = jedisPool.getResource()) {
            Pipeline pipeline = jedis.pipelined();
            callback.execute(pipeline);
            pipeline.sync();
        } catch (Exception e) {
            throw new RedisException("Pipeline failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void transaction(TransactionCallback callback) {
        try (Jedis jedis = jedisPool.getResource()) {
            Transaction transaction = jedis.multi();
            callback.execute(transaction);
            transaction.exec();
        } catch (Exception e) {
            throw new RedisException("Transaction failed: " + e.getMessage(), e);
        }
    }

    @Override
    public Object eval(String script, List<String> keys, List<String> args) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.eval(script, keys, args);
        } catch (Exception e) {
            throw new RedisException("Eval script failed: " + e.getMessage(), e);
        }
    }

    @Override
    public void close() {
        if (jedisPool != null && !jedisPool.isClosed()) {
            jedisPool.close();
        }
    }
} 